import { useCallback, useRef, useState } from "react";
import useLatestRef from "./useLatestRef";

type UseFetchStreamOptions<T> = {
  // data: T;
  fetchFn: (
    data: T,
    signal: AbortSignal,
  ) => Promise<ReadableStream<Uint8Array>>;
  onProgress: (data: string) => void;
  onError?: (error: any) => void;
};

type State = {
  isPending: boolean;
  isError: boolean;
  error: any;
};

export default function useFetchStream<T>(options: UseFetchStreamOptions<T>) {
  const [state, setState] = useState<State>({
    isPending: false,
    isError: false,
    error: null,
  });
  const optionsRef = useLatestRef(options);
  const abortControllerRef = useRef<AbortController>();

  const fetcher = useCallback(
    async (data: T) => {
      const { fetchFn, onProgress, onError } = optionsRef.current;
      const abortController = new AbortController();
      abortControllerRef.current = abortController;
      setState({ isPending: true, isError: false, error: null });
      try {
        const stream = await fetchFn(data, abortController.signal);
        const reader = stream.pipeThrough(new TextDecoderStream()).getReader();
        while (true) {
          const { done, value } = await reader.read();
          if (done) {
            break;
          }
          onProgress(value);
        }
        setState({ isPending: false, isError: false, error: null });
      } catch (error) {
        console.log(error);
        onError?.(error);
        setState({ isPending: false, isError: true, error });
      }
    },
    [optionsRef],
  );

  const cancel = useCallback(() => {
    if (abortControllerRef.current) {
      abortControllerRef.current.abort(new Error("用户主动取消"));
      abortControllerRef.current = undefined;
    }
  }, []);

  return { ...state, refetch: fetcher, cancel };
}
